package com.xqls.server.netty;

import com.alibaba.fastjson.JSON;
import com.xqls.bean.OperationRecordBean;
import com.xqls.biz.SokectBiz;
import com.xqls.dal.model.DeviceSchema;
import com.xqls.server.dto.FluSoketCommonDto;
import com.xqls.server.dto.send.PingDto;
import com.xqls.thread.SokectRunAble;
import com.xqls.thread.ThreadPoolExecutorUtil;
import com.xqls.util.ContextUtil;
import com.xqls.util.DictionaryEnums;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.ReferenceCountUtil;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.Date;

/**
 * Created by Skeyedu on 2017/7/12.
 */
public class TcpFluServerHandler extends ChannelInboundHandlerAdapter {
    public TcpFluServerHandler() {
        super();
    }

    private static final Logger LOG = LoggerFactory
            .getLogger(TcpFluServerHandler.class);

    private OperationRecordBean activeOperationRecordBean;

    //往channel map中添加channel信息
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        super.channelActive(ctx);
        NettyTCPServer.getChannelMap().put(getIPString(ctx) + ctx.channel().hashCode(), ctx.channel());
        if (activeOperationRecordBean == null) {
            activeOperationRecordBean = new OperationRecordBean();
            activeOperationRecordBean.setOperationType(DictionaryEnums.NET_WORK.getCode().toString());
            activeOperationRecordBean.setRecordContent("上线");

        }
        activeOperationRecordBean.setRecordTime(new Date());

    }

    //往channel map中删除channel信息
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        super.channelInactive(ctx);
        NettyTCPServer.getChannelMap().remove(getIPString(ctx) + ctx.channel().hashCode());
        SokectBiz sokectBiz = (SokectBiz) ContextUtil.getBean(SokectBiz.class);
        if (activeOperationRecordBean.getEnterpriseNo() != null) {
            sokectBiz.channelInactive(activeOperationRecordBean.getEnterpriseNo());
        }
        activeOperationRecordBean = null;
    }


    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        FluSoketCommonDto soketCommonDto = (FluSoketCommonDto) msg;
        if (soketCommonDto != null) {
            try{


            LOG.info("接收到协议" +Thread.currentThread().getName()+ soketCommonDto.toString());
            boolean deviceSchemaBean= ContextUtil.checkAddress(soketCommonDto.getAdress());
            if(!deviceSchemaBean){
                return ;
            }
            LOG.info("flugkeyMap:"+ JSON.toJSONString(NettyTCPServer.getChannelKeyMap()));
            LOG.info("flugchannleMap:"+JSON.toJSONString(NettyTCPServer.getChannelMap()));
            NettyTCPServer.checkChannelExsit(soketCommonDto.getAdress(), getIPString(ctx) + ctx.channel().hashCode());

            //上线操作日志保存 上线只会触发一次
            if (activeOperationRecordBean.getEnterpriseNo() == null) {
                activeOperationRecordBean.setEnterpriseNo(soketCommonDto.getAdress());
                soketCommonDto.setActiveOperationRecordBean(activeOperationRecordBean);
            }

             new  SokectRunAble(soketCommonDto).call();
            }catch (Exception e){
                throw e;
            }finally {
                ReferenceCountUtil.release(soketCommonDto);
            }


        }
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {

        System.out.println("server channelReadComplete.." + ctx.channel());
        super.channelReadComplete(ctx);
        ctx.alloc().buffer().discardReadBytes();

    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        LOG.error("exceptionCaught!", cause);
        // ctx.close();
    }


    @Override//超时触发该方法
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt)
            throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent event = (IdleStateEvent) evt;
            if (event.state().equals(IdleState.ALL_IDLE)) {
                // 超时关闭channel
                ctx.close();
                String channelKey = getIPString(ctx) + ctx.channel().hashCode();
               LOG.info(channelKey+"READER_IDLE");

                String adress = NettyTCPServer.getAdressByChannel(channelKey);
                if (StringUtils.isNotEmpty(adress)) {
                    NettyTCPServer.getChannelMap().remove(adress);
                    NettyTCPServer.getChannelKeyMap().remove(adress);
                }
            } else if (event.state().equals(IdleState.WRITER_IDLE)) {
               LOG.info("WRITER_IDLE");
            } else if (event.state().equals(IdleState.READER_IDLE)) {

                // 发送心跳
                String adress = NettyTCPServer.getAdressByChannel(getIPString(ctx) + ctx.channel().hashCode());
                LOG.info(adress+"READER_IDLE");
                if (adress != null) {
                    PingDto pingDto = new PingDto();
                    pingDto.setAdress(adress);
                    ctx.channel().write(pingDto);
                    ctx.channel().flush();
                }

            }
        }
        super.userEventTriggered(ctx, evt);
    }


    public static String getIPString(ChannelHandlerContext ctx) {
        String ipString = "";
        String socketString = ctx.channel().remoteAddress().toString();
        int colonAt = socketString.indexOf(":");
        ipString = socketString.substring(1, colonAt);
        return ipString;
    }
}
